package com.cnap.multiclouldmgmt.controller;

import com.alibaba.fastjson.JSON;
import com.cnap.multiclouldmgmt.model.BasicValueModel;
import com.cnap.multiclouldmgmt.model.CommonResult;
import com.cnap.multiclouldmgmt.model.RepByPage;
import com.cnap.multiclouldmgmt.model.enums.AlarmLevelEnum;
import com.cnap.multiclouldmgmt.model.enums.CloudVendorsEnum;
import com.cnap.multiclouldmgmt.model.enums.ErrorInjectOrderEnum;
import com.cnap.multiclouldmgmt.model.k8sModels.K8sClusterModel;
import com.cnap.multiclouldmgmt.model.k8sModels.NodeModel;
import com.cnap.multiclouldmgmt.model.k8sModels.PodModel;
import com.cnap.multiclouldmgmt.model.k8sModels.SvcModel;
import com.cnap.multiclouldmgmt.model.knowledge.ErrorConfigModel;
import com.cnap.multiclouldmgmt.model.knowledge.ErrorInjectModel;
import com.cnap.multiclouldmgmt.model.knowledge.ErrorInjectSceneModel;
import com.cnap.multiclouldmgmt.model.knowledge.KnowledgePO;
import com.cnap.multiclouldmgmt.model.microSvc.*;
import com.cnap.multiclouldmgmt.model.microSvc.alg.CpuRiskTrendModel;
import com.cnap.multiclouldmgmt.model.microSvc.alg.ForececastRiskCpuModel;
import com.cnap.multiclouldmgmt.model.microSvc.alg.IndicatorHistoryModel;
import com.cnap.multiclouldmgmt.model.microSvc.assist.*;
import com.cnap.multiclouldmgmt.repository.master.K8sClusterInfoMapper;
import com.cnap.multiclouldmgmt.service.CacheService;
import com.cnap.multiclouldmgmt.service.HealthService;
import com.cnap.multiclouldmgmt.service.MicroSvcInfoService;
import com.cnap.multiclouldmgmt.util.TokenUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * 对接其他后端相关系统
 *
 * @author dyq
 */
@Api(tags = "v2.0的健康诊断的相关接口")
@RequestMapping(path = "/cnap/multicloudmgmt/v1/health")
@RestController
@ResponseBody
public class HealthController {

    private final static Logger LOGGER = LoggerFactory.getLogger(HealthController.class);

    @Autowired
    private CacheService cacheService;

    @Autowired
    private K8sClusterInfoMapper k8sClusterInfoMapper;

    @Autowired
    private MicroSvcInfoService microSvcInfoService;

    @Autowired
    private HealthService healthService;
    //中心服务器地址ip
    @Value("${center.ip}")
    private  String centerIp;

    //中心服务器地址ip
    @Value("${center.apisixPort}")
    private  String centerApisixPort;

    /**
     * 获取所有云的类型
     *
     * @return List<String>
     */
    @ApiOperation(value = "7-1 获取所有云的类型", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getAllCloudVendors", method = RequestMethod.GET)
    public CommonResult<List<String>> createVmResource() {

        try {

            List<String> result = CloudVendorsEnum.getAllCloudVendors();

            return CommonResult.success(result);

        } catch (Exception e) {

            LOGGER.error("HealthController getAllCloudVendors error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 返回所有部署了集群的区域
     *
     * @return List<String>
     */
    @ApiOperation(value = "7-2 获取所有集群的region", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getAllUseRegion", method = RequestMethod.GET)
    public CommonResult<List<RegionModel>> getAllUseRegion(String cloudVendor, String regionId) {

        try {

            List<RegionModel> result = k8sClusterInfoMapper.getAllUseRegion(cloudVendor, regionId);

            return CommonResult.success(result);

        } catch (Exception e) {

            LOGGER.error("HealthController getAllUseRegion error", e);

            return CommonResult.failed(e.getMessage());
        }
    }


    /**
     * 返回所有部署了集群的可用区
     *
     * @return List<String>
     */
    @ApiOperation(value = "7-3 获取所有集群的zone", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getAllUseZone", method = RequestMethod.GET)
    public CommonResult<List<ZoneModel>> getAllUseZone(String cloudVendor, String regionId, String zoneId) {

        try {

            List<ZoneModel> result = k8sClusterInfoMapper.getAllUseZone(cloudVendor, regionId, zoneId);

            return CommonResult.success(result);

        } catch (Exception e) {

            LOGGER.error("HealthController getAllUseZone error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 返回所有部署了集群名称
     *
     * @return List<String>
     */
    @ApiOperation(value = "7-4 返回所有部署了微服务的集群名称", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getAllClusterName", method = RequestMethod.GET)
    public CommonResult<List<K8sClusterModel>> getAllClusterName(String cloudVendor, String regionId, String zoneId, String clusterName) {

        try {

            List<K8sClusterModel> result = new ArrayList<>();
            String userName = TokenUtils.getUserName();

            List<SvcModel> svcModels = microSvcInfoService.getAllSvcModelForMicroSvc(cloudVendor, regionId, zoneId, clusterName, "", userName);
            if (!svcModels.isEmpty()) {
                Map<String, K8sClusterModel> clusterNameMap = new HashMap<>();
                for (SvcModel svcModel : svcModels) {
                    K8sClusterModel k8sClusterModel = new K8sClusterModel();
                    k8sClusterModel.setK8sClusterName(svcModel.getK8sClusterName());
                    k8sClusterModel.setCloudVendor(svcModel.getCloudVendor());
                    k8sClusterModel.setZoneId(svcModel.getZoneId());
                    k8sClusterModel.setRegionId(svcModel.getRegionId());
                    clusterNameMap.put(svcModel.getK8sClusterName(),k8sClusterModel);
                }

                result.addAll(clusterNameMap.values());
            }

            return CommonResult.success(result);

        } catch (Exception e) {

            LOGGER.error("HealthController getAllClusterName error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 返回所有微服务名
     *
     * @return List<String>
     */
    @ApiOperation(value = "7-5 返回所有微服务名", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getAllMicroSvcName", method = RequestMethod.GET)
    public CommonResult<List<SvcModel>> getAllMicroSvcName(String cloudVendor, String regionId, String zoneId, String clusterName, String microSvcName) {

        try {

            List<SvcModel> result = new ArrayList<>();
            String userName = TokenUtils.getUserName();

            List<SvcModel> svcModels =
                    microSvcInfoService.getAllSvcModelForMicroSvc(cloudVendor, regionId, zoneId, clusterName, microSvcName, userName);
            if (!svcModels.isEmpty()) {
                Map<String,SvcModel> svcModelMap = new HashMap<>();
                for (SvcModel svcModel : svcModels) {
                    svcModelMap.put(svcModel.getMicroServiceName(),svcModel);
                }
                result.addAll(svcModelMap.values());
            }

            return CommonResult.success(result);

        } catch (Exception e) {

            LOGGER.error("HealthController getAllMicoSvcName error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 返回集群和微服务的情况
     *
     * @return List<String>
     */
    @ApiOperation(value = "7-6 返回集群和微服务的情况", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getClusterMicroSvcInfos", method = RequestMethod.GET)
    public CommonResult<List<CloudVendorWithSvcInfoModel>> getClusterMicroSvcInfos(String cloudVendor, String regionId, String zoneId, String clusterName, String microSvcName) {

        try {
            List<CloudVendorWithSvcInfoModel> cloudVendorWithSvcInfoModels = new ArrayList<>();
            String userName = TokenUtils.getUserName();

            List<ClusterMicroSvcModel> result =
                    microSvcInfoService.getClusterMicroSvcInfos(cloudVendor, regionId, zoneId, clusterName, microSvcName, userName);

            //对result进行处理
            Map<String,Map<String,Map<String,ClusterMicroSvcModel>>> mapForCloud = new HashMap<>();
            for (ClusterMicroSvcModel tmp:result){

                if (!mapForCloud.containsKey(tmp.getCloudVendor())){
                    mapForCloud.put(tmp.getCloudVendor(),new HashMap<>());
                }

                Map<String,Map<String,ClusterMicroSvcModel>> mapForRegion = mapForCloud.get(tmp.getCloudVendor());

                if (!mapForRegion.containsKey(tmp.getRegionId())){
                    mapForRegion.put(tmp.getRegionId(),new HashMap());
                }

                mapForRegion.get(tmp.getRegionId()).put(tmp.getK8sClusterName(),tmp);
            }

            for (String cloudType:mapForCloud.keySet()){

                CloudVendorWithSvcInfoModel cloudVendorWithSvcInfoModel = new CloudVendorWithSvcInfoModel();
                cloudVendorWithSvcInfoModel.setCloudVendor(cloudType);
                cloudVendorWithSvcInfoModel.setRegionWithSvcInfoModel(new ArrayList<>());

                for (String regionStr:mapForCloud.get(cloudType).keySet()){

                    RegionWithSvcInfoModel regionWithSvcInfoModel = new RegionWithSvcInfoModel();
                    regionWithSvcInfoModel.setRegionId(regionStr);
                    regionWithSvcInfoModel.setClusterMicroSvcModels(
                            new ArrayList<>(mapForCloud.get(cloudType).get(regionStr).values()));
                    cloudVendorWithSvcInfoModel.getRegionWithSvcInfoModel().add(regionWithSvcInfoModel);

                }

                cloudVendorWithSvcInfoModels.add(cloudVendorWithSvcInfoModel);
            }

            return CommonResult.success(cloudVendorWithSvcInfoModels);

        } catch (Exception e) {

            LOGGER.error("HealthController getAllMicoSvcName error", e);

            return CommonResult.failed(e.getMessage());
        }
    }


    /**
     * 返回微服务的使用情况，包含历史数据
     *
     * @return List<String>
     */
    @ApiOperation(value = "7-7 返回微服务的使用情况(最近24小时，每个小时一个点)", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getMicroSvcUseInfo", method = RequestMethod.GET)
    public CommonResult<MicroSvcUseInfoModel> getMicroSvcUseInfo(String cloudVendor, String regionId, String zoneId, String clusterName, String microSvcName) {

        try {

            String userName = TokenUtils.getUserName();
            MicroSvcUseInfoModel microSvcUseInfoModel =
                    microSvcInfoService.getMicroSvcUseInfo(cloudVendor,regionId,zoneId,clusterName,microSvcName,userName);

            return CommonResult.success(microSvcUseInfoModel);

        } catch (Exception e) {

            LOGGER.error("HealthController getMicroSvcUseInfo error", e);

            return CommonResult.failed(e.getMessage());
        }
    }


    /**
     * 返回微服务的使用情况，包含历史数据
     *
     * @return List<String>
     */
    @ApiOperation(value = "7-8 返回指定集群下，若干微服务的cpu使用率和请求响应时间",httpMethod = "POST", notes = "")
    @RequestMapping(path = "/getAlarmSvcInfo",method = RequestMethod.POST)
    public CommonResult<AlarmSvcInfoModel> getAlarmSvcInfo(@RequestBody SvcReqInfoModel svcReqInfoModel) {

        try {

            String userName = TokenUtils.getUserName();

            AlarmSvcInfoModel result =
                    microSvcInfoService.getMicroSvcsInfo(
                            svcReqInfoModel.getK8sClusterName(),svcReqInfoModel.getMicroSvcNames(), userName);

            return CommonResult.success(result);

        }catch (Exception e){

            LOGGER.error("HealthController getAlarmSvcInfo error",e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 查询健康度
     *
     * @return 结果
     */
    @ApiOperation(value = "7-9 获取健康度", httpMethod = "GET", notes = "查询健康度")
    @GetMapping("/value")
    public CommonResult<String> queryHealthValue() {
        String result = healthService.getHealthValue();
        return CommonResult.success(result);
    }

    /**
     * 查询知识库
     *
     * @return 结果
     */
    @ApiOperation(value = "7-10 查询知识库", httpMethod = "GET", notes = "查询知识库")
    @GetMapping("/knowledge")
    public CommonResult<List<KnowledgePO>> queryKnowledge() {
        List<KnowledgePO> result = healthService.getAllKnowledge();
        return CommonResult.success(result);
    }

    /**
     * 查看优化趋势
     *
     * @return 结果
     */
    @ApiOperation(value = "7-11 查看优化趋势",httpMethod = "GET", notes = "查看优化趋势")
    @RequestMapping(path = "/getOptTrends",method = RequestMethod.GET)
    public CommonResult<List<BasicValueModel>> getOptTrends(String indicatorId) {
        LinkedList<BasicValueModel> result = new LinkedList<>();

        List<IndicatorHistoryModel> indicatorHistoryModels =
                microSvcInfoService.getIndicatorHistoryModels(indicatorId);

        if (!indicatorHistoryModels.isEmpty()){

            for (IndicatorHistoryModel indicatorHistoryModel:indicatorHistoryModels) {
                BasicValueModel basicValueModel = new BasicValueModel();
                basicValueModel.setRecordTime(indicatorHistoryModel.getCreateTime());

                switch (indicatorHistoryModel.getIndicatorKey()){
                    case("单副本消耗CPU量"):
                        basicValueModel.setValue(indicatorHistoryModel.getCpuUsage());
                        break;
                    case("单个副本消耗内存量"):
                        basicValueModel.setValue(indicatorHistoryModel.getMemUsage());
                        break;
                    case("单个副本磁盘读写速率"):
                        basicValueModel.setValue(indicatorHistoryModel.getDiskThroughput());
                        break;
                    case("单副本磁盘读写秒均次数"):
                        basicValueModel.setValue(indicatorHistoryModel.getDiskIops());
                        break;
                    case("单副本网络带宽"):
                        basicValueModel.setValue(indicatorHistoryModel.getNetBandwidth());
                        break;
                }

                result.add(basicValueModel);
            }
        }

        //需要30个点，所以现在小于30个点的要补0
        if (result.size() < 30){

            for (int i = 0;i < (30 - result.size());i++){
                BasicValueModel basicValueModel = new BasicValueModel();
                basicValueModel.setValue("0");
                result.addFirst(basicValueModel);
            }
        }

        return CommonResult.success(result);
    }

    /**
     * 查看优化趋势
     *
     * @return 结果
     */
    @ApiOperation(value = "7-12 cpu风险预测",httpMethod = "GET", notes = "cpu风险预测")
    @RequestMapping(path = "/getCpuRiskTrends",method = RequestMethod.GET)
    public CommonResult<ForececastRiskCpuModel> getCpuRiskTrends(String microSvcId){

        ForececastRiskCpuModel result = microSvcInfoService.getCpuRishTrends(microSvcId);

        if (result.getAlarm_thresh() == null){
            return CommonResult.failed("get cpu risk trend fail");
        }

        return CommonResult.success(result);
    }


    /**
     * 获取大屏消息中心的情况
     *
     * @return 结果
     */
    @ApiOperation(value = "7-13 获取大屏消息中心的情况",httpMethod = "GET", notes = "获取大屏消息中心的情况")
    @RequestMapping(path = "/getMsgCenterInfos",method = RequestMethod.GET)
    public CommonResult<RepByPage<MsgInfo>> getMsgCenterInfos(int pageSize, int pageNo){

        RepByPage<MsgInfo> result = new RepByPage<>();
        result.setPageSize(pageSize);
        result.setPageNo(pageNo);

        String userName = TokenUtils.getUserName();

        result = microSvcInfoService.getMsgCenterInfos(userName,pageSize,pageNo);

        return CommonResult.success(result);
    }

    /**
     * 删除一条消息
     *
     * @return 结果
     */
    @ApiOperation(value = "7-14 删除消息中心的一条消息",httpMethod = "DELETE", notes = "删除消息中心的一条消息")
    @RequestMapping(path = "/delMsgCenterInfo",method = RequestMethod.DELETE)
    public CommonResult<Void> delMsgCenterInfo(int id){

        microSvcInfoService.delMsgCenterInfo(id);

        return CommonResult.successMsg("delete msg success");
    }


    /**
     * 删除一条消息
     *
     * @return 结果
     */
    @ApiOperation(value = "7-15 获取调试场景的语句",httpMethod = "GET", notes = "删除消息中心的一条消息")
    @RequestMapping(path = "/getErrorInjectScenes",method = RequestMethod.GET)
    public CommonResult<RepByPage<ErrorInjectSceneModel>> getErrorInjectScenes(String keyword, int pageSize, int pageNo){

        RepByPage<ErrorInjectSceneModel> result = healthService.getErrorInjectScenes(keyword,pageSize,pageNo);

        return CommonResult.success(result);
    }

    /**
     * 返回所有微服务名
     *
     * @return List<String>
     */
    @ApiOperation(value = "7-16 返回所有微服务名", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getAllMicroSvcNameByPage", method = RequestMethod.GET)
    public CommonResult<RepByPage<SvcModel>> getAllMicroSvcNameByPage(String cloudVendor, String regionId, String zoneId, String clusterName, String microSvcName,
                                                                 int pageSize,int pageNo) {

        try {

            RepByPage<SvcModel> result = new RepByPage<>();
            result.setPageNo(pageNo);
            result.setPageSize(pageSize);
            String userName = TokenUtils.getUserName();

            List<SvcModel> svcModels =
                    microSvcInfoService.getAllSvcModelForMicroSvc(cloudVendor, regionId, zoneId, clusterName, microSvcName, userName);
            if (!svcModels.isEmpty()) {
                //map做去重
                Map<String,SvcModel> svcModelMap = new HashMap<>();
                for (SvcModel svcModel : svcModels) {
                    svcModel.setPath("http://" + centerIp + ":" + centerApisixPort + "/"+svcModel.getPath());
                    svcModelMap.put(svcModel.getMicroServiceName(),svcModel);
                }
                List<SvcModel> svcModelsNoRepeat = new ArrayList<>(svcModelMap.values());
                result.setTotalNum(svcModelsNoRepeat.size());
                int beginIndex = (pageNo -1)*pageSize;
                int endIndex = pageNo*pageSize;
                if (endIndex > svcModelsNoRepeat.size()){
                    endIndex = svcModelsNoRepeat.size();
                }
                result.setResult(svcModelsNoRepeat.subList(beginIndex,endIndex));
            }

            return CommonResult.success(result);

        } catch (Exception e) {

            LOGGER.error("HealthController getAllMicoSvcName error", e);

            return CommonResult.failed(e.getMessage());
        }
    }


    /**
     * 返回微服务的使用情况，包含历史数据
     *
     * @return List<String>
     */
    @ApiOperation(value = "7-17 返回指定集群下，若干节点的cpu使用率和请求响应时间",httpMethod = "POST", notes = "")
    @RequestMapping(path = "/getAlarmNodeInfo",method = RequestMethod.POST)
    public CommonResult<AlarmNodeInfoModel> getAlarmNodeInfo(@RequestBody NodeAlarmReqInfoModel nodeAlarmReqInfoModel) {

        try {

            AlarmNodeInfoModel result = microSvcInfoService.getAlarmNodeInfo(nodeAlarmReqInfoModel);

            return CommonResult.success(result);

        }catch (Exception e){

            LOGGER.error("HealthController getAlarmNodeInfo error",e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     *
     *
     * @return 结果
     */
    @ApiOperation(value = "7-18 获取当前用户已经配置的故障命令",httpMethod = "GET", notes = "获取当前用户已经配置的故障命令")
    @RequestMapping(path = "/getErrorInjects",method = RequestMethod.GET)
    public CommonResult<RepByPage<ErrorInjectModel>> getErrorInjects(String keyword, int pageSize, int pageNo){

        RepByPage<ErrorInjectModel> result = new RepByPage<>();

        try {
            result = healthService.getErrorInjects(keyword, pageSize, pageNo);

            return CommonResult.success(result);
        }catch (Exception e){
            LOGGER.error("getErrorInjects error keyword={}",keyword,e);
            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     *
     *
     * @return 结果
     */
    @ApiOperation(value = "7-19 执行故障注入",httpMethod = "GET", notes = "执行故障注入")
    @RequestMapping(path = "/runErrorInject",method = RequestMethod.GET)
    public CommonResult<Void> runErrorInject(int id){

        try {
            healthService.runErrorInject(id);

        return CommonResult.successMsg("run success");

        }catch (Exception e){
            LOGGER.error("runErrorInject error id={}",id,e);
            return CommonResult.failed(e.getMessage());
        }
    }


    /**
     *
     *
     * @return 结果
     */
    @ApiOperation(value = "7-20 删除故障注入",httpMethod = "GET", notes = "删除故障注入")
    @RequestMapping(path = "/delErrorInject",method = RequestMethod.GET)
    public CommonResult<Void> delErrorInject(int id){

        try {
            healthService.delErrorInject(id);

            return CommonResult.successMsg("del success");
        }catch (Exception e){
            LOGGER.error("delErrorInject error id={}",id,e);
            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     *
     *
     * @return 结果
     */
    @ApiOperation(value = "7-21 停止故障注入",httpMethod = "GET", notes = "停止故障注入")
    @RequestMapping(path = "/stopErrorInject",method = RequestMethod.GET)
    public CommonResult<Void> stopErrorInject(int id){

        try {

            healthService.stopErrorInject(id);
            return CommonResult.successMsg("stop success");
        }catch (Exception e){
            LOGGER.error("stopErrorInject error id={}",id,e);
            return CommonResult.failed(e.getMessage());
        }
    }


    /**
     *
     *
     * @return 结果
     */
    @ApiOperation(value = "7-22 生成一条故障注入",httpMethod = "POST", notes = "生成一条故障注入")
    @RequestMapping(path = "/addErrorInject",method = RequestMethod.POST)
    public CommonResult<Void> addErrorInject(@RequestBody ErrorConfigModel errorConfigModel){

        try {

            String userName = TokenUtils.getUserName();
            LOGGER.warn("addErrorInject param={} username={}", JSON.toJSONString(errorConfigModel),userName);
            healthService.addErrorInject(errorConfigModel,userName);
            return CommonResult.successMsg("Add success");
        }catch (Exception e){
            LOGGER.error("addErrorInject failed errorName={}",errorConfigModel.getErrorName(),e);
            return CommonResult.failed(e.getMessage());
        }
    }

}
